<?php

namespace common\models\trade;

use Yii;
use common\models\shop\Order;
use common\models\original\Users;

/**
 * This is the model class for table "{{%trade}}".
 *
 * @property int $id
 * @property string $user_id 用户UID
 * @property string $trade_no 交易号
 * @property string $paymode 交易支付方式
 * @property string $total 交易总金额
 * @property string $cash 交易需支付现金
 * @property string $credit 交易需支付积分
 * @property int $balance 结算方式：-1支出，1收入
 * @property int $status 交易状态
 * @property string $platform 创建交易来源平台
 * @property string $partner_id 合作商家ID
 * @property string $bizno 商家业务订单号
 * @property string $subject 交易名称
 * @property string $body 交易描述
 * @property string $expire_time 交易过期时间
 * @property string $created_at 交易创建时间
 * @property string $updated_at 交易更新时间
 * @property string $mark 交易备注
 * @property string $return_url 同步回调地址
 * @property string $unified_no 统一订单号
 */
class Trade extends \common\db\ActiveRecord {

    use \common\traits\Constants;
    use \common\traits\TimestampBehavior;

    /**
     * 订单支付方式
     * @var PAYMODE_WECHAT  wechat  微信支付
     * @var PAYMODE_ALIPAY  alipay  支付宝支付
     * @var PAYMODE_APPLE   apple   苹果支付
     * @var PAYMODE_CREDIT  credit  积分支付
     */
    const PAYMODE_WECHAT = 'wechat';
    const PAYMODE_ALIPAY = 'alipay';
    const PAYMODE_APPLE = 'apple';
    const PAYMODE_CREDIT = 'credit';

    /**
     * 交易状态
     * @var STATUS_CENCELED -2  已取消
     * @var STATUS_CLOSED   -1  已关闭,未付款交易超时关闭，或支付完成后全额退款
     * @var STATUS_DEFAULT  0   默认状态,交易创建，等待买家付款
     * @var STATUS_WAITPAY  1   等待交易付款
     * @var STATUS_SUCCESS  2   已支付,交易支付成功
     * @var STATUS_FINISHED 3   已支付,交易结束，不可退款
     */
    const STATUS_CENCELED = -2;
    const STATUS_CLOSED = -1;
    const STATUS_DEFAULT = 0;
    const STATUS_WAITPAY = 1;
    const STATUS_SUCCESS = 2;
    const STATUS_FINISHED = 3;

    /**
     * @var BALANCE_PAYMENT 1 收入
     * @var BALANCE_REDUCE -1 支出
     */
    const BALANCE_PAYMENT = 1;
    const BALANCE_REDUCE = -1;

    /**
     * @var AUTO_EXPIRED_TIME 900 交易自动过期时间
     */
    const AUTO_EXPIRED_TIME = 900;
    const VERIFY_DEFAULT = 0;
    const VERIFY_SUCCESS = 1;

    /**
     * @inheritdoc
     */
    public static function tableName() {
        return '{{%trade}}';
    }

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['trade_no', 'total', 'cash', 'credit'], 'required'],
            [['user_id', 'balance', 'status', 'partner_id', 'expire_time', 'created_at', 'updated_at'], 'integer'],
            ['paymode', 'string'],
            [['total', 'cash', 'credit'], 'number'],
            [['trade_no', 'bizno', 'unified_no'], 'string', 'max' => 32],
            [['platform'], 'string', 'max' => 50],
            [['subject'], 'string', 'max' => 64],
            [['body'], 'string', 'max' => 128],
            [['return_url', 'mark'], 'string', 'max' => 255],
            [['trade_no'], 'unique'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'user_id' => '用户UID',
            'trade_no' => '交易号',
            'paymode' => '支付方式',
            'total' => '交易总金额',
            'cash' => '支付现金',
            'credit' => '支付积分',
            'balance' => '结算方式',
            'status' => '交易状态',
            'platform' => '创建交易来源平台',
            'partner_id' => '合作商家ID',
            'bizno' => '商家业务订单号',
            'subject' => '交易名称',
            'body' => '交易描述',
            'return_url' => '回调地址',
            'expire_time' => '交易过期时间',
            'created_at' => '交易创建时间',
            'updated_at' => '交易更新时间',
            'mark' => '交易备注',
            'return_url' => '同步回调地址',
            'unified_no' => '统一订单号',
            'verify_time' => '核对时间',
        ];
    }

    /**
     * Finds order by tradeno
     *
     * @param string $tradeno
     * @return static|null
     */
    public static function findByTradeNo($tradeno) {
        return static::findOne(['trade_no' => $tradeno]);
    }

    /**
     * Finds order by tradeno
     *
     * @param string $tradeno
     * @return static|null
     */
    public function setMark($mark) {
        $temp = '[' . date('Y-m-d H:i:s') . ']' . $mark;
        $this->mark .= $temp . "\n";
    }

    /**
     * Finds order by bizno
     *
     * @param string $bizno
     * @return static|null
     */
    public static function findByBizno($bizno, $autoCreated = false) {
        if ($autoCreated === false) {
            return static::findOne(['bizno' => $bizno]);
        }
        $model = static::find()
        ->where(['bizno' => $bizno])
        ->orderBy(['created_at' => SORT_DESC]);

        $model = static::findOne(['bizno' => $bizno]);
    }

    /**
     * Find trade
     */
    public function getOrders() {
        return $this->hasMany(TradeOrder::className(), ['trade_id' => 'id']);
    }

    /**
     * Find trade
     */
    public function getConnectUser() {
        return $this->hasOne(\common\models\user\UserConnect::className(), ['user_id' => 'user_id']);
    }

    /**
     * Find trade
     */
    public function getPaymentOrder() {
        return $this->getOrders()->where(['balance' => TradeOrder::BALANCE_PAYMENT, 'status' => TradeOrder::STATUS_SUCCESS]);
    }

    /**
     * Find trade
     */
    public function getRefundOrder() {
        return $this->getOrders()->where(['balance' => TradeOrder::BALANCE_REFUND, 'status' => TradeOrder::STATUS_SUCCESS]);
    }

    public function getUsers() {
        return $this->hasOne(Users::className(), ['id' => 'user_id']);
    }

    /**
     * 生成唯一交易号
     */
    public function generateTn($paymode, $from) {
        $pcode = 0;
        if ($paymode == static::PAYMODE_ALIPAY) {
            $pcode = 2;
        } elseif ($paymode == static::PAYMODE_WECHAT) {
            $pcode = 4;
        }
        $date = date('Ymd');
        $rules = [
            'paymode' => $pcode,
            'from' => str_pad(dechex($from), 2, "0", STR_PAD_LEFT),
            'date' => substr($date, 2),
        ];
        do {
            $micro = round((microtime(true) - strtotime($date)) * 10000);
            $rules['micro'] = str_pad($micro, 9, 0, STR_PAD_RIGHT);
            $tn = implode($rules);
            $record = static::find()->where(['trade_no' => $tn])->exists();
        } while ($record);
        $this->paymode = $paymode;
        $this->partner_id = $from;
        return $this->trade_no = $tn;
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getPartners() {
        return $this->hasOne(\common\models\trade\Partner::className(), ['id' => 'partner_id'])->inverseOf('trade');
    }

    /**
     * 查询 累计支付 现金/积分
     * 累计退款 现金/积分
     * 以及剩余可退 现金/积分
     * @param $bizno
     * @return array
     */
    public function findPayByBizno($bizno) {
        $data = [
            'pay' => [
                'cash' => 0,
                'credit' => 0,
                'total' => 0,
            ],
            'reduce' => [
                'cash' => 0,
                'credit' => 0,
                'total' => 0,
            ],
            'diff' => [
                'cash' => 0,
                'credit' => 0,
                'total' => 0,
            ],
            'paymode' => ''
        ];

        //支付交易单
        $tradePay = static::findOne(['bizno' => $bizno, 'status' => self::STATUS_SUCCESS, 'balance' => self::BALANCE_PAYMENT]);
        if (!empty($tradePay)) {
            $data['pay']['total'] = $tradePay->total;
            $data['pay']['credit'] = $tradePay->credit;
            $data['pay']['cash'] = $tradePay->cash;
            $data['paymode'] = $tradePay->paymode;
        }

        //累计退款
        $tradeRefunds = TradeRefund::find()
        ->andFilterWhere(['from_trade_no' => $tradePay->trade_no])
        ->andFilterWhere(['>', 'status', TradeRefund::STATUS_WAITPAY])
        ->all();

        foreach ($tradeRefunds as $tradeRefund) {
            $data['reduce']['total'] += $tradeRefund->total;
            $data['reduce']['cash'] += $tradeRefund->cash;
            $data['reduce']['credit'] += $tradeRefund->credit;
        }

        $data['diff']['cash'] = $data['pay']['cash'] - $data['reduce']['cash'];
        $data['diff']['credit'] = $data['pay']['credit'] - $data['reduce']['credit'];
        $data['diff']['total'] = $data['pay']['total'] - $data['reduce']['total'];

        return $data;
    }

    public function getBizOrder() {
        return $this->hasOne(Order::className(), ['order_no' => 'bizno']);
    }

    public function getUnifiedTrades() {
        return $this->hasMany(static::className(), ['unified_no' => 'unified_no']);
    }

    public static function findAllByUnifiedNo($unified_no) {
        return static::findAll(['unified_no' => $unified_no, 'status' => self::STATUS_SUCCESS]);
    }

}
